package cn.xjfcloud.onedriveserver.util;

import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.HashMap;
import java.util.Map;

import org.springframework.util.StringUtils;

import cn.xjfcloud.onedriveserver.pojo.dto.ApiConfig;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;

public class ApiUtil {
	private final static MediaType FORM_MEDIA_TYPE = MediaType.get("application/x-www-form-urlencoded");
	private final static MediaType JSON_MEDIA_TYPE = MediaType.get("application/json");
	private final static String GET_TOKEN_ORIGIN_REQUEST_BODY = "client_id={client_id}&redirect_uri={redirect_uri}&client_secret={client_secret}"
			+ "&code={code}&grant_type=authorization_code";
	private final static String GET_TOKEN_BY_REFRESH_TOKEN = "client_id={client_id}&redirect_uri={redirect_uri}&client_secret={client_secret}"
			+ "&refresh_token={refresh_token}&grant_type=refresh_token";

	private final static Integer SUCCESS = 200;

	/**
	 * 利用code获取access_token(后简称token)和refresh_token(用作token过期后获取token，需要在app的permission设置offline_access)
	 * 
	 * @param code
	 * @return
	 * @throws IOException
	 */
	public static String getAuthTokenAndReFreshToken(String code,ApiConfig apiConfig) throws IOException {
		OkHttpClient client = new OkHttpClient();
		// 1.构建请求体
		String requestBody = GET_TOKEN_ORIGIN_REQUEST_BODY.replace("{client_id}", apiConfig.getClientId())
				.replace("{redirect_uri}", "http://localhost").replace("{client_secret}", apiConfig.getClientSecret())
				.replace("{code}", code);
		RequestBody body = RequestBody.create(FORM_MEDIA_TYPE, requestBody);
		// 2. 创建请求的Request 对象
		Request request = new Request.Builder().url("https://login.microsoftonline.com/common/oauth2/v2.0/token")
				.post(body).build();

		try (Response response = client.newCall(request).execute()) {
			return response.body().string();
		}
	}

	/**
	 * 利用refresh_token获取tokens
	 * 
	 * @param refreshToken
	 * @return
	 * @throws IOException
	 */
	public static String getTokenByRefreshToken(ApiConfig apiConfig) throws IOException {
		OkHttpClient client = new OkHttpClient();
		// 1.构建请求体
		String requestBody = GET_TOKEN_BY_REFRESH_TOKEN.replace("{client_id}", apiConfig.getClientId())
				.replace("{redirect_uri}", "http://localhost").replace("{client_secret}", apiConfig.getClientSecret())
				.replace("{refresh_token}", apiConfig.getRefreshToken());
		RequestBody body = RequestBody.create(FORM_MEDIA_TYPE, requestBody);
		// 2. 创建请求的Request 对象
		Request request = new Request.Builder().url("https://login.microsoftonline.com/common/oauth2/v2.0/token")
				.post(body).build();

		try (Response response = client.newCall(request).execute()) {
			return response.body().string();
		}
	}

	/**
	 * 获取下载链接
	 * 
	 * @param filePath
	 * @returnOneDrive
	 * @throws IOException
	 */
	public static Map<String, Object> getDownloadInputStream(String filePath, String range, ApiConfig apiConfig) throws IOException {
		Map<String, Object> resultMap = new HashMap<String, Object>();
		URL url = new URL("https://graph.microsoft.com/v1.0/me/drive/root:/" + filePath + ":/content");
		HttpURLConnection httpConn = (HttpURLConnection) url.openConnection();
		httpConn.setUseCaches(false);
		httpConn.setFollowRedirects(false);
		String auth = "bearer  {token}".replace("{token}", apiConfig.getAccessToken());
		httpConn.setRequestProperty("Authorization", auth);
		if (!StringUtils.isEmpty(range)) {
			httpConn.setRequestProperty("Range", range);
		}
		int responseCode = httpConn.getResponseCode();
		Long contentLength = httpConn.getContentLengthLong();
		
		switch (responseCode) {
		case 200:
			resultMap.put("contentLength", contentLength);
			resultMap.put("inputStream", httpConn.getInputStream());
			resultMap.put("contentRange", null);
			return resultMap;
		case 302:
			// String redirectUrl = httpConn.getHeaderField("Content-Location");
			String redirectUrl = httpConn.getHeaderField("Location");
			resultMap = getRedircetUrlInputStream(redirectUrl, range);
			return resultMap;
		case 206:
			resultMap.put("contentLength", contentLength);
			String contenRange = httpConn.getHeaderField("Content-Range");
			resultMap.put("inputStream", httpConn.getInputStream());
			resultMap.put("contentRange", contenRange);
			return resultMap;
		default:
			throw new IOException("get download url fail");
		}
	}

	/**
	 * 带range请求头的inputstream
	 * 
	 * @param downloadUrl
	 * @param range
	 * @return
	 * @throws IOException
	 */
	public static Map<String, Object> getRedircetUrlInputStream(String downloadUrl, String range) throws IOException {
		Map<String, Object> resultMap = new HashMap<String, Object>();
		URL url = new URL(downloadUrl);
		URLConnection conn = url.openConnection();
		// 设置请求range
		if (!StringUtils.isEmpty(range)) {
			conn.setRequestProperty("Range", range);
		}
		InputStream inStream = conn.getInputStream();
		String contentRange = conn.getHeaderField("Content-Range");
		Long contentLength = conn.getContentLengthLong();
		resultMap.put("contentLength", contentLength);
		resultMap.put("inputStream", inStream);
		// 获取onedrive 返回的content-range
		resultMap.put("contentRange", contentRange);
		return resultMap;
	}

	/**
	 * 获取uploadSession
	 * 
	 * @param filePath
	 * @param fileName
	 * @return
	 * @throws IOException
	 */
	public static String getUploadSession(String filePath, String fileName, ApiConfig apiConfig) throws IOException {
		String jsonString = "{" + "  \"item\": {"
				+ "    \"@odata.type\": \"microsoft.graph.driveItemUploadableProperties\","
				+ "    \"@microsoft.graph.conflictBehavior\": \"rename\"," + "    \"name\": \"" + fileName + "\""
				+ "  }" + "}";
		String url = "https://graph.microsoft.com/v1.0/me/drive/root:/" + filePath + fileName + ":/createUploadSession";
		System.out.println(url);
		System.out.println(jsonString);
		String auth = "{token}".replace("{token}", apiConfig.getAccessToken());
		OkHttpClient client = new OkHttpClient();
		// 1.构建请求体
		RequestBody body = RequestBody.create(JSON_MEDIA_TYPE, "");
		// 2. 创建请求的Request 对象
		Request request = new Request.Builder().url(url).addHeader("Authorization", auth).post(body).build();
		// 获取返回值
		try (Response response = client.newCall(request).execute()) {
			return response.body().string();
		}
	}

	/**
	 * 取消一个upload
	 * @param url
	 * @param apiConfig
	 * @return
	 * @throws IOException
	 */
	public static Integer cancelUpload(String url, ApiConfig apiConfig) throws IOException {
		String auth = "{token}".replace("{token}", apiConfig.getAccessToken());
		OkHttpClient client = new OkHttpClient();
		Request request = new Request.Builder().url(url).delete().build();
		try (Response response = client.newCall(request).execute()) {
			return response.code();
		}
	}
	
	/**
	 * 删除文件
	 * @param filePath
	 * @param apiConfig
	 * @return
	 * @throws IOException
	 */
	public static Integer deleteOnedriveFile(String filePath, ApiConfig apiConfig) throws IOException {
		URL url = new URL("https://graph.microsoft.com/v1.0/me/drive/root:/" + filePath);
		String auth = "{token}".replace("{token}", apiConfig.getAccessToken());
		OkHttpClient client = new OkHttpClient();
		Request request = new Request.Builder().url(url).addHeader("Authorization", auth).delete().build();
		try (Response response = client.newCall(request).execute()) {
			return response.code();
		}
	}
	
	/**
	 * 获取认证链接
	 * @param apiConfig
	 * @return
	 */
	public static String getAuthCodeUrl(ApiConfig apiConfig) {
		String authCodeUrl = "https://login.microsoftonline.com/common/oauth2/v2.0/authorize?client_id="
				+ apiConfig.getClientId()
				+ "&scope=Files.ReadWrite offline_access&response_type=code&redirect_uri=http://localhost";
		return authCodeUrl;
	}
	
	
}
